# -*- coding: utf-8 -*-
# @file    : websocket-server
# @Date    : 2020/11/19
# @Author  :
# @Version : 1.0.0
import asyncio
import os

import websockets
from websockets import WebSocketServerProtocol, InvalidStatusCode

from .log import logger as _logger
from . import ws_client


@property
def _name(self):
    return "WS服务(%s)" % id(self)


WebSocketServerProtocol.name = _name


async def server(websocket, path):
    """
    websocket 主业务逻辑
    :param websocket:
    :param path:
    :return:
    """
    _logger.info("%s: 启动", websocket.name)
    try:
        recv_q = asyncio.Queue()
        send_q = asyncio.Queue()

        asyncio.run_coroutine_threadsafe(receive_handle(websocket, recv_q), asyncio.get_event_loop())
        asyncio.run_coroutine_threadsafe(send_handle(websocket, send_q), asyncio.get_event_loop())

        # 先假装认证成功
        await send_q.put('{"auth":true}')
        while not websocket.closed:
            try:
                await ws_client.client(path, send_q, _parent_socket=websocket)
                _logger.error("%s->WS-客户端: 异常退出, %s ,1秒后自动重启", websocket.name, "连接断开")
            except Exception as e:
                if isinstance(e, InvalidStatusCode) and e.status_code == 401:
                    e = "认证失败, 请检查cookie是否过期"
                _logger.error("%s->WS-客户端: 异常退出, %s ,1秒后自动重启", websocket.name, e)
            await asyncio.sleep(1)

    except Exception as e:
        _logger.error("%s: 异常退出, %s", websocket.name, e)
    finally:
        _logger.info("%s: 关闭", websocket.name)


async def receive_handle(websocket, queue):
    """
    接收浏览器推送的消息, 并存入队列(recv_q), 方便异步处理
    :param websocket:
    :param queue:
    :return:
    """
    while not websocket.closed:
        data = await websocket.recv()
        # 暂时接收到的消息没有用 所以暂时不用存入队列中
        # 简单打印即可
        _logger.info("%s: 接到推送: %s", websocket.name, data)
        # await queue.put(data)


async def send_handle(websocket, queue):
    """
    发送消息, 从队列(send_q)中取出消息, 推送给浏览器
    :param websocket:
    :param queue:
    :return:
    """
    while not websocket.closed:
        msg = await queue.get()
        await websocket.send(msg)


def test():
    start_server = websockets.serve(server, 'localhost', 5005)
    asyncio.get_event_loop().run_until_complete(start_server)
    asyncio.get_event_loop().run_forever()


def start(host, port):
    _logger.info("启动 WebSocket * Running on ws://%s:%s", host, port)
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    start_server = websockets.serve(server, host, port)
    asyncio.get_event_loop().run_until_complete(start_server)
    asyncio.get_event_loop().run_forever()
